package com.bo.day20240929;

import java.util.ArrayList;

/**
 * 判断是否搜索二叉树
 * 思路1：
 * 1.中序遍历，判断是否递增
 * ----------------------
 * 思路2：
 * 1.获取到左子树的最大值,判断当前节点是否大于左子树的最大值
 * 2.获取到右子树的最小值，判断当前节点是否小于右子树的最小值
 * 3.判断左右子树是否都是搜索二叉树
 *
 * @Author: gpb
 * @Date: 2024/9/30 10:00
 * @Description:
 */
public class IsSearchBinaryTree {
    public static class Node {
        public int value;
        public Node left;
        public Node right;

        public Node (int v) {
            value = v;
        }
    }

    public static class Info {
        boolean isBST; // 是否搜索二叉树
        int leftMax; // 左子树的最大值
        int rightMin; // 右子树的最小值

        public Info (boolean isBST, int leftMax, int rightMin) {
            this.isBST = isBST;
            this.leftMax = leftMax;
            this.rightMin = rightMin;
        }
    }

    /**
     * 中序遍历方式
     * @param head
     * @return
     */
    public static boolean isBST1(Node head) {
        if (head == null) {
            return true;
        }
        ArrayList<Node> arr = new ArrayList<>();
        in(head, arr);
        for (int i = 1; i < arr.size(); i++) {
            if (arr.get(i).value <= arr.get(i - 1).value) {
                return false;
            }
        }
        return true;
    }
    public static void in(Node head, ArrayList<Node> arr) {
        if (head == null) {
            return;
        }
        in(head.left, arr);
        arr.add(head);
        in(head.right, arr);
    }

    /**
     *  思路2：
     *  1.获取到左子树的最大值,判断当前节点是否大于左子树的最大值
     *  2.获取到右子树的最小值，判断当前节点是否小于右子树的最小值
     *  3.判断左右子树是否都是搜索二叉树
     * @param node
     * @return
     */
    public static boolean isSearchBinaryTree (Node node) {
        if (node == null) {
            return true;
        }
        return process(node).isBST;
    }

    public static Info process (Node node) {
        // 递归终止条件
        if (node == null) {
            // 空树，不好处理，返回空
            return null;
        }
        // 拿到左树的信息
        Info leftInfo = process(node.left);
        // 拿到右树的信息
        Info rightInfo = process(node.right);
        boolean isBST = true; // 是否搜索二叉树
        int leftMax = node.value; // 左子树的最大值
        int rightMin = node.value; // 右子树的最小值
        // 获取最大值
        if (leftInfo != null) {
            leftMax = Math.max(leftMax, leftInfo.leftMax);
        }
        if (rightInfo != null) {
            leftMax = Math.max(leftMax, rightInfo.leftMax);
        }
        // 获取最小值
        if (leftInfo != null) {
            rightMin = Math.min(rightMin, leftInfo.rightMin);
        }
        if (rightInfo != null) {
            rightMin = Math.min(rightMin, rightInfo.rightMin);
        }
        // 判断是否搜索二叉树
        // 只要左右子树有个不是搜索二叉树，整个树都不是
        if (leftInfo != null && !leftInfo.isBST) {
            isBST = false;
        }
        if (rightInfo != null && !rightInfo.isBST) {
            isBST = false;
        }
        // 当前节点的值，比左右子树最大值小，比右子树最小值大，才是搜索二叉树
        if (leftInfo != null && leftInfo.leftMax >= node.value) {
            isBST = false;
        }
        if (rightInfo != null && rightInfo.rightMin <= node.value) {
            isBST = false;
        }
        return new Info(isBST, leftMax, rightMin);
    }

    // for test
    public static Node generateRandomBST(int maxLevel, int maxValue) {
        return generate(1, maxLevel, maxValue);
    }

    // for test
    public static Node generate(int level, int maxLevel, int maxValue) {
        if (level > maxLevel || Math.random() < 0.5) {
            return null;
        }
        Node head = new Node((int) (Math.random() * maxValue));
        head.left = generate(level + 1, maxLevel, maxValue);
        head.right = generate(level + 1, maxLevel, maxValue);
        return head;
    }

    public static void main(String[] args) {
        int maxLevel = 4;
        int maxValue = 100;
        int testTimes = 1000000;
        for (int i = 0; i < testTimes; i++) {
            Node head = generateRandomBST(maxLevel, maxValue);
            if (isBST1(head) != isSearchBinaryTree(head)) {
                System.out.println("Oops!");
            }
        }
        System.out.println("finish!");
    }

}
